package storage.v1;

import java.util.ArrayList;
import java.util.Collection;

import com.onpositive.commons.platform.registry.IAdaptable2;
import com.onpositive.data.IPropertyConstants;
import com.onpositive.dataminer.core.DefaultUniverse;
import com.onpositive.knowledge.model.IThing;
import com.onpositive.knowledge.model.IUniverse;
import com.onpositive.mediawiki.dataminer.MediaWikiUniverse;
import com.onpositive.mediawiki.dataminer.WikiThing;
import com.onpositive.mediawiki.propertyparser.ParsedCategory;
import com.onpositive.mediawiki.propertyparser.ParsedDocument;
import com.onpositive.mediawiki.propertyparser.PropertyCharacteristic;
import com.onpositive.semantic.model.api.meta.DefaultMetaKeys;
import com.onpositive.semantic.model.api.meta.IHasMeta;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.semantic.model.api.realm.IRealm;
import com.onpositive.semantic.model.api.realm.IRealmProvider;
import com.onpositive.semantic.model.api.realm.Realm;
import com.onpositive.units.ParsedIdent;
import com.onpositive.units.ParsedProperty;
import com.onpositive.units.ParsedSection;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;
import com.onpositive.units.UndefinedParsedValue;
import com.onpositive.utils.IStringPoolProvider;
import com.onpositive.utils.StringPool;
import com.onpositive.wikipedialookup.AbstractRefsLookUp;
import com.onpositive.wikipedialookup.AbstractRefsLookUp2;
import com.onpositive.wikipedialookup.WikipediaRefsLookup;

abstract public class CategoryStorage implements
					  IStringPoolProvider,
					  IPropertyProvider,
					  IWikiStorage,
					  IParserIdLookup,
					  IRealmProvider<IThing>,
					  IAdaptable2,
					  ITableInfoContainer {

	public static final int FORCE_RELOAD_FLAG = 1 << 0;
	public static final int FORCE_REPARSE_FLAG = 1 << 1;
	protected ParsedCategory category;

	public CategoryStorage() {
		super();
	}

	@Override
	public IProperty getProperty(Object obj, String name) {
		
		IProperty special = getSpecialProperty( name) ;
		if( special != null )
			return special ;
		
		PropertyCharacteristic pChar = category.getCharacteristics( name ) ;

		if( pChar == null )
			return null ;
		
		IProperty result = createProperty(pChar);
		if( obj == null )			
			return result ;
		
		ParsedDocument pd = null ;		
		if( obj instanceof String )
		{
			String documentName = (String) obj ;
			pd = category.getParsedDocument( documentName ) ;
		}
		if( obj instanceof ParsedDocument )
			pd = (ParsedDocument) obj ;
		
		if( pd != null && pd.getProperty( name ) != null )
			return result ;
		
		return null;
	}

	@Override
	public Iterable<IProperty> getProperties(Object obj) {
		
		ArrayList<IProperty> result = new ArrayList<IProperty>() ;		
		
		addSpecialProperties( result ) ;
		
		for( PropertyCharacteristic pChar : category.getChracteristicsMap().values() ){
//			if( pChar.getCharacteristic( IPropertyConstants.CHAR_PROPERTY_NAME_LABEL ).equals( IPropertyConstants.TEXT_CONTENT_PROPERTY_NAME) )
//				continue ;			
			result.add( createProperty(pChar) ) ;
		}
		
		
		
		return result ;
	}
	
	public IProperty getProperty(String propertyName)
	{
		if( propertyName == null || category == null )
			return null ;
		
		IProperty special = getSpecialProperty(propertyName) ;
		if( special != null )
			return special ;		
		
		PropertyCharacteristic pChar = category.getCharacteristics(propertyName) ;
		return pChar != null ? createProperty(pChar) : null ;
	}	
	
	abstract protected void addSpecialProperties( Collection<IProperty> col ) ;
	abstract protected IProperty getSpecialProperty( String propertyName ) ;
	abstract protected IProperty createProperty( PropertyCharacteristic pChar ) ;

	@Override
	public ParsedDocument getParsedDocument(String id) {
	
		return category.getParsedDocument( id );
	}

	@Override
	public IRealm<IThing> getRealm(IHasMeta model, Object parentObject, Object object) {
		
		Collection<ParsedDocument> docs ;// = category.getDocumentsList() ;
		
//		IUniverse universe = null ;
//		if( parentObject != null )
//		{
//			if( !(parentObject instanceof IUniverse )  )
//				return null ;
//			
//			universe = (IUniverse) parentObject ;
//		}
		
		if( parentObject == null )
			docs = category.getDocumentsList() ;
		
		else{
			if( !( parentObject instanceof String ) )
				return null ;
			
			String categoryName = (String) parentObject ;
		
			if( categoryName.length() == 0 )
				docs = category.getDocumentsList() ;
			else
				docs = category.getSubcategoryDocuments( categoryName ) ;
		}
		Realm<IThing> result = new Realm<IThing>() ;
		for( ParsedDocument pd : docs )
			result.add( createThing( pd.getName() ) ) ;
	
		return result;
	}

	

	public ParsedCategory getCategory() {
		return category;
	}

	public void setCategory(ParsedCategory category) {
		this.category = category;
	}

	@Override
	public String getParserId(String propertyName) {
		
		if( category == null )
			return null ;
		IProperty property = DefaultUniverse.getInstance().getProperty(null, propertyName);
		String stringValue = DefaultMetaKeys.getStringValue(property, PropertyCharacteristic.CHAR_PARSER_ID_LABEL);
		if (stringValue!=null){
			return stringValue;
		}
		PropertyCharacteristic pChar = category.getCharacteristics(propertyName) ;
		if( pChar == null )
			return null ;
		
		return pChar.getCharacteristic( PropertyCharacteristic.CHAR_PARSER_ID_LABEL ) ;
	}
	
	
	@Override
	public StringPool getStringPool( String name )
	{
		if( name.equals(IPropertyConstants.WIKI_REFS_POOL_ID ) )
			return category.getWikiRefsPool() ;
		
		return null ;
	}
	
	public void resolveWikipediaRefs(){
		
		AbstractRefsLookUp2 wrl = new AbstractRefsLookUp2( category.getLinks(), category.getLinkCaptions() ) ;//.getInstance() ;
		
//		ParsedProperty pr = category.getParsedDocument("Curtiss P-6 Hawk").getProperty("caption") ;
//		for( ParsedValue pv : pr.getValues() )
//		{
//			
//			String valueId = pv.getId();
//			if( valueId == ParsedValueSequence.ID || valueId == ParsedSection.ID )
//			{
//				String str = pv.getValueAsString() ;
//				wrl.processString( str, false, "Curtiss P-6 Hawk", pr.getName() ) ;
//			}
//		}
		
		ArrayList<ParsedValue> toDelete = new ArrayList<ParsedValue>() ;
		ArrayList<ParsedValue> toAdd = new ArrayList<ParsedValue>() ;
		for( ParsedDocument pd : category.getDocumentsList() )
		{
			System.out.print( pd.getName() +"\n\n") ;
			for( ParsedProperty pp : pd.getProps().values() )
			{
				toDelete.clear() ;
				toAdd.clear() ;
				
				for( ParsedValue pv : pp.getValues() )
				{
					
					String valueId = pv.getId();
					if( valueId == ParsedValueSequence.ID || valueId == ParsedSection.ID )
					{
						String str = pv.getValueAsString() ;
						String newStr = wrl.processString( str, valueId == ParsedSection.ID, pd.getName(), pp.getName() ) ;
						if( newStr != null && !str.equals( newStr ) ){
							toDelete.add( pv ) ;
							if(valueId.equals(ParsedValueSequence.ID)){
								ParsedValueSequence newPv = new ParsedValueSequence( pv.getComment() + ", refs resolved") ;
								ValuesExtractorV1.processValueSubstring( newPv, newStr, "refs_resolver") ;
								toAdd.add( newPv ) ;
							}
							if(valueId.equals(ParsedSection.ID)){
								ParsedSection newPs = new ParsedSection( newStr, pv.getComment() + ", refs resolved" ) ;
								toAdd.add( newPs ) ;
							}							
						}
							
					}
				}
				for( ParsedValue pv : toDelete  )
					pp.removeValue( pv ) ;
				
				for( ParsedValue pv : toAdd  )
					pp.addValue( pv ) ;				
			}
			
		}		
		
		WikipediaRefsLookup.disposeInstance() ;
	}
	

	@SuppressWarnings("unchecked")
	public <T> T getAdapter(Class<T> adapter)
	{
		if( adapter == IStringPoolProvider.class )
			return (T) category ;
		
		if( adapter == ParsedCategory.class )
			return (T) category ;
		
		if( adapter == IParserIdLookup.class )
			return (T) this ;
		
		if( adapter == IPropertyProvider.class )
			return (T) this ;
		
		if( adapter == ITableInfoContainer.class )
			return (T) this ;
		
		if( adapter == ParsedCategory.class )
			return (T) getCategory() ;
		
		return null ;
	}

	
	abstract protected IThing createThing( Object name ) ;
	
	protected ArrayList<ITableInfo> tableInfoList = new ArrayList<ITableInfo>() ;
	
	protected ArrayList<ITableInfo> getTableInfoList() {
		return tableInfoList;
	}

	@Override
	public void addTableInfo( ITableInfo ti ){
		tableInfoList.add(ti) ;
	}
	
	@Override
	public void clearTableInfo() {
		tableInfoList.clear() ;		
	}
	
	protected void processTableInfo()
	{
		if( tableInfoList.size() == 0 )
			return ;
		try{
			( new BasicTableInfoProcessor( this ) ).processTableInfo() ;			
		}
		finally{
			tableInfoList.clear() ;
		}
	}
	

}